package linker

import (
	"debug/elf"
	"risc-v/ld/pkg/utils"
)

// GotSection Global offset table
// 主要是用于动态链接，但是在重定位也会用到的
// Thread Local storage 的数据会存储到全局偏移量表
// glibc 中有很多 .tsl section 的数据
// 这里仅仅处理一部分满足,需要即可
type GotSection struct {
	Chunk
	GotTpSymbols []*Symbol
}

// NewGotSections  构造函数
func NewGotSections() *GotSection {
	g := &GotSection{Chunk: NewChunk()}
	g.Name = ".got"
	g.SectionHeader.Type = uint32(elf.SHT_PROGBITS)               // 规定
	g.SectionHeader.Flags = uint64(elf.SHF_ALLOC | elf.SHF_WRITE) // 规定
	g.SectionHeader.AddrAlign = 0
	return g
}

// AddGotTpSymbol 增加一个 Symbol 到 Got 中
func (g *GotSection) AddGotTpSymbol(s *Symbol) {
	s.GotTpIndex = int32(g.SectionHeader.Size / 8)
	g.SectionHeader.Size += 8
	g.GotTpSymbols = append(g.GotTpSymbols, s)
}

type GotEntry struct {
	Index int64
	Val   uint64
}

func (g *GotSection) GetEntries(ctx *Context) []GotEntry {
	entries := make([]GotEntry, 0)
	for _, symbol := range g.GotTpSymbols {
		index := symbol.GotTpIndex
		entries = append(entries, GotEntry{
			Index: int64(index),
			Val:   symbol.GetAddr() - ctx.TpAddr,
		})
	}

	return entries
}

func (g *GotSection) CopyBuf(ctx *Context) {
	base := ctx.Buf[g.SectionHeader.Offset:]
	for _, entry := range g.GetEntries(ctx) {
		utils.Write(base[entry.Index*8:], entry.Val)
	}
}
